# -*- coding: utf-8 -*-
# &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
# D7Cl0ud360
# 邮箱: 18656042877@163.com
# 作者：'sugar'
# 公司网址： http://www.dtcloud360.com/
# Copyright 中亿丰信息科技(苏州)有限公司
# 日期：2023/5/27 10:40
# &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
from copy import deepcopy
from dtcloud import http
from collections import defaultdict
from dtcloud.addons.rest_controller.handlers import RestController
from ..serializer.menu import MenuBodyModel, MenuButtonBodyModel


class MenuRestController(RestController):
    _model = "dt.menu"
    _method_map = {
        'list': 'GET',
        'create': 'POST',
        'update': 'PUT',
        'destroy': 'DELETE',
    }
    _default_auth = 'token'
    _prefix = "/api"
    _type = 'jsonify'

    def create(self, **data):
        if data.get("mtype") == "menu":
            data = MenuBodyModel(**data).dict(exclude_none=True)
        elif data.get("mtype") == "button":
            data = MenuButtonBodyModel(**data).dict(exclude_none=True)
        else:
            return self.make_response(None, status=-1, msg="类型异常!")

        return super().create(**data)

    def update(self, req_id, **data):
        mtype = data.pop('mtype', None)
        if 'status' in data and len(data) == 1:
            return super().update(req_id, **data)

        if mtype == "menu":
            data = MenuBodyModel(**data).dict(exclude_none=True)
        elif mtype == "button":
            data = MenuButtonBodyModel(**data).dict(exclude_none=True)
        else:
            return self.make_response(None, status=-1, msg="类型异常!")

        return super().update(req_id, **data)

    def list(self, name=None, status=None, **kwargs):
        """后台获取所有菜单列表"""
        menu_list_fields = ('id', "name", "seq_no", "code", "mtype",
                            "parent_id", 'route', "icon", "path", "hidden",
                            "keep_alive", "status", "target")
        button_list_fields = ('id', 'name', "parent_id", "code", "route", "method", "status", "mtype", "seq_no")

        database = http.request.env
        menu_domains = [('mtype', '=', 'menu')]
        if name:
            menu_domains.append(('name', 'ilike', name))
        if status:
            menu_domains.append(('status', '=', status not in ('false', False, 0, '0')))

        menu_list = database['dt.menu'].sudo().search_read(menu_domains, fields=menu_list_fields, order="seq_no asc")
        button_list = database['dt.menu'].sudo().search_read(
            [('mtype', '=', 'button')], fields=button_list_fields, order="seq_no asc"
        )

        root_menu_map = self._menu_list(menu_list, button_list)
        return self.make_response(list(root_menu_map.values()))

    def _menu_list(self, menu_list, button_list):
        button_map = defaultdict(list)
        for button in button_list:
            if not button['parent_id']:
                continue
            button_map.setdefault(button['parent_id'][0], []).append(button)

        # 构建拥有的菜单、按钮关系
        for menu in menu_list:
            if menu['id'] in button_map:
                menu.setdefault('children', []).extend(button_map[menu['id']])

        # 构建排序
        menu_list.sort(
            key=lambda ele: int(ele['parent_id']) if ele['parent_id'] is False else ele['parent_id'][0], reverse=True)

        # 处理父子关系
        menu_map = {menu['id']: menu for menu in menu_list if menu['parent_id']}
        root_menu_map = {menu['id']: menu for menu in menu_list if not menu['parent_id']}
        # 构建普通菜单之间的关系
        menu_map_copy = deepcopy(menu_map)
        for name, menu in menu_map_copy.items():
            if menu['parent_id'][0] in menu_map:
                menu_map[menu['parent_id'][0]].setdefault('children', []).append(menu_map[name])
                del menu_map[name]

        # 构建子菜单、根菜单关系
        for name, menu in menu_map.items():
            if menu['parent_id'][0] in root_menu_map:
                root_menu_map[menu['parent_id'][0]].setdefault("children", []).append(menu)
            else:
                root_menu_map[name] = menu

        return root_menu_map

    @http.route("/api/dt_menu/options", auth='token', methods=['GET'], type='jsonify')
    def dt_menu(self, menu_id=None):
        """获取菜单项"""
        domains = [('mtype', '=', "menu"), ('status', '=', True)]
        if menu_id:
            domains.append(('id', '!=', int(menu_id)))

        res = http.request.env['dt.menu'].sudo().search_read(
            domains, fields=('id', 'name', 'parent_id'), order='seq_no asc'
        )
        for r in res:
            r["label"] = r['name']
            r["value"] = r['id']

        options = self._menu_list(res, [])
        return self.make_response(list(options.values()))

    @http.route("/api/dt_menu/permission", auth='token', methods=['GET'], type="jsonify")
    def get_menu_permission(self, code=None):
        """动态获取菜单列表"""
        user = http.request.env.user

        if code:
            menu_ins = http.request.env['dt.menu'].sudo().search(
                [('code', '=', code), ('status', '=', True),
                 ('mtype', '=', 'menu'), ('parent_id', '=', None)], limit=1)
            if not menu_ins:
                return self.make_response(None, status=-1, msg='获取系统菜单异常!')

            return self.make_response(user.menu_list(menu_ins.id))

        # 获取工作台应用权限
        menu_fields = ('id', "name", "seq_no", "code", 'route', "icon", "path")
        if user.superuser:
            menu_list = http.request.env['dt.menu'].sudo().search_read([
                ('status', '=', True), ('mtype', '=', 'menu'), ('parent_id', '=', None)],
                fields=menu_fields,
                order='seq_no asc')
        else:
            role_ids = user.role_ids.filtered(lambda x: x.status is True)
            if not role_ids:
                menu_list = []
            else:
                menu_ids = role_ids.menu_ids.filtered(
                    lambda x: x.mtype == 'menu' and x.status is True and not x.parent_id
                )
                menu_list = menu_ids.read(fields=menu_fields)
                menu_list.sort(key=lambda ele: ele['seq_no'])

        return self.make_response(menu_list)

